﻿using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;

namespace MyK3CloudCore.IOC.Cache;

/// <summary>
/// 缓存服务(内存)
/// </summary>
//[DebuggerStepThrough]
public class MemoryCacheService : ICacheService
{
    private readonly IMemoryCache cache;
    private CancellationTokenSource _resetCacheToken = new();
    public MemoryCacheService() : this(new MemoryCache(Options.Create(new MemoryCacheOptions()))) { }
    public MemoryCacheService(IMemoryCache cache)
    {
        this.cache = cache;
    }
    public void Add<V>(string key, V value)
    {
        Add(key, value, 1200);
    }

    public void Add<V>(string key, V value, int cacheDurationInSeconds)
    {
        MemoryCacheEntryOptions options = new()
        {
            AbsoluteExpiration = DateTime.Now.AddSeconds(cacheDurationInSeconds),
            SlidingExpiration = TimeSpan.FromSeconds(cacheDurationInSeconds)
        };
        cache.Set(key, value, options);
        using var entry = cache.CreateEntry(key);
        entry.SetOptions(options);
        entry.Value = value;
        entry.AddExpirationToken(new CancellationChangeToken(_resetCacheToken.Token));
    }

    public bool ContainsKey<V>(string key)
    {
        return cache.TryGetValue(key, out _);
    }

    public V Get<V>(string key)
    {
        _ = cache.TryGetValue(key, out V value);
        return value;
    }

    public IEnumerable<string> GetAllKey<V>()
    {
        const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
        var _coherentState = cache.GetType().GetField("_coherentState", flags)?.GetValue(cache);
        if (_coherentState == null) yield break;
        var entries = _coherentState.GetType().GetField("_entries", flags)?.GetValue(_coherentState);
        if (entries is not IDictionary cacheItems) yield break;
        foreach (DictionaryEntry cacheItem in cacheItems)
        {
            yield return cacheItem.Key.ToString();
        }
    }

    public V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = int.MaxValue)
    {
        var result = create();
        return cache.GetOrCreate(cacheKey, e =>
        {
            MemoryCacheEntryOptions options = new()
            {
                AbsoluteExpiration = DateTime.Now.AddSeconds(cacheDurationInSeconds),
                SlidingExpiration = TimeSpan.FromSeconds(cacheDurationInSeconds)
            };
            e.SetOptions(options);
            e.Value = result;
            e.AddExpirationToken(new CancellationChangeToken(_resetCacheToken.Token));
            return result;
        });
    }

    public void Remove<V>(string key)
    {
        cache.Remove(key);
    }

    public void RemoveAll()
    {
        _resetCacheToken.Cancel();
        _resetCacheToken.Dispose();
        _resetCacheToken = new CancellationTokenSource();
    }
}

[DebuggerStepThrough]
public class MemoryCacheHelper<V>
{

    #region 全局变量
    private static MemoryCacheHelper<V> _instance = null;
    private static readonly object _instanceLock = new();
    private readonly MemoryCacheService _cache;

    #endregion

    #region 构造函数

    private MemoryCacheHelper()
    {
        _cache = new MemoryCacheService();
    }
    #endregion

    #region  属性
    /// <summary>         
    ///根据key获取value     
    /// </summary>         
    /// <value></value>      
    public V this[string key] => _cache.Get<V>(key);
    #endregion

    #region 公共函数

    /// <summary>         
    /// key是否存在       
    /// </summary>         
    /// <param name="key">key</param>         
    /// <returns>  存在<c>true</c> 不存在<c>false</c>. </returns>         
    public bool ContainsKey(string key)
    {
        return _cache.ContainsKey<V>(key);
    }

    /// <summary>         
    /// 获取缓存值         
    /// </summary>         
    /// <param name="key">key</param>         
    /// <returns></returns>         
    public V Get(string key)
    {
        return _cache.Get<V>(key);
    }

    /// <summary>         
    /// 获取实例 （单例模式）       
    /// </summary>         
    /// <returns></returns>
    public static MemoryCacheHelper<V> GetInstance()
    {
        if (_instance == null)
        {
            lock (_instanceLock)
            {
                _instance ??= new MemoryCacheHelper<V>();
            }
        }
        return _instance;
    }

    /// <summary>         
    /// 插入缓存(默认20分钟)        
    /// </summary>         
    /// <param name="key"> key</param>         
    /// <param name="value">value</param>          
    public void Add(string key, V value)
    {
        Add(key, value, 60 * 20);
    }

    /// <summary>         
    /// 插入缓存        
    /// </summary>         
    /// <param name="key"> key</param>         
    /// <param name="value">value</param>         
    /// <param name="cacheDurationInSeconds">过期时间单位秒</param>         
    public void Add(string key, V value, int cacheDurationInSeconds = 20 * 60)
    {
        if (cacheDurationInSeconds <= 0) { cacheDurationInSeconds = 20 * 60; }
        _cache.Add(key, value, cacheDurationInSeconds);
    }



    /// <summary>         
    /// 删除缓存         
    /// </summary>         
    /// <param name="key">key</param>         
    public void Remove(string key)
    {
        _cache.Remove<V>(key);
    }

    /// <summary>
    /// 清除所有缓存
    /// </summary>
    public void RemoveAll()
    {
        _cache.RemoveAll();
    }


    /// <summary>
    /// 获取所有缓存key
    /// </summary>
    /// <returns></returns>
    public IEnumerable<string> GetAllKey()
    {
        return _cache.GetAllKey<V>();
    }
    #endregion
}